home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / adlip.arj / TIMER.ASM < prev    next >
Assembly Source File  |  1988-12-02  |  6KB  |  386 lines

  1. ;
  2. ; 08h interrupt driver (from BYTE special issue, nov. 86, pp 249-262)
  3. ;
  4. ; Adaptation: Marc Savary, Ad Lib Inc, 1986/11/03
  5. ;
  6.  
  7. ;    This module allows you to change the timer-0 interrupt rate,
  8. ;   without affecting the rate at which the currently installed
  9. ;   routine is called ( 18.2 Hz).
  10. ;
  11. ;    A user function (TimeOut()) is called after 'n'
  12. ;   interrupts, 'n' being reset after each call.
  13.  
  14.  
  15. ; Originally written for Lattice C Compiler, small model.  Adapted to
  16. ; Microsoft by using macros (notably BEGIN, P_END, EXTERN).  A flag for the
  17. ; type of compiler is defined in the file VERSION.INC.  According to this
  18. ; flag, the file containing the appropriate equates and macros is then
  19. ; included.
  20.  
  21.   INCLUDE VERSION.INC      ;*** compilation flags are defined in this file ***
  22.  
  23.   IF MICROSOFT
  24.     INCLUDE CMICRO.MAC     ;memory model & equates for Microsoft environment
  25.   ELSE
  26.     INCLUDE DOS.MAC        ;memory model & equates for Lattice environment
  27.   ENDIF
  28.  
  29.   INCLUDE COMMON.MAC       ;macros common to both environments
  30.  
  31.  
  32. clk_int equ 08h     ; timer-0 interrupt vector number
  33.  
  34.  
  35. ; ============= vector structure ==========
  36.  
  37. vector    struc
  38. regip    dw    ?
  39. regcs    dw    ?
  40. vector    ends
  41.  
  42.  
  43. ; ========================= DATA SEGMENT ============================
  44.  
  45.     DSEG
  46.  
  47. int_stack_size        equ    512
  48.  
  49. the_stack         db    int_stack_size DUP ('S')
  50. interrupt_stack_top dw  0
  51.  
  52.     ENDDS
  53.         
  54.  
  55. ;========================== CODE SEGMENT ============================
  56.  
  57.   IF MICROSOFT
  58.     PSEG  <TIMER>
  59.   ELSE
  60.     PSEG
  61.   ENDIF
  62.  
  63.   EXTERN  TimeOut
  64.  
  65.  
  66. clkdivh    dw    ?        ; actual divisor ... high
  67. clkdivl    dw    ?        ; ... low
  68. clkmod    dw    ?        ; divisor modulus
  69.  
  70. int08    vector    <>
  71.  
  72. appl_ds dw    ?
  73. old_ss    dw    ?        ; interrupted code's SS
  74. old_sp    dw    ?        ; SP .......
  75.  
  76. soundDelay    dw    ?    ; delay counter
  77. user_routine_on    db    (?)    ; flag to avoid reentrance
  78.  
  79.  
  80.  
  81.  
  82. ;    clkrate()
  83. ;
  84. ;    change timer-0 divider
  85. ;    IN : AX count divisor
  86. ;
  87.     IF    LPROG
  88. clkrate    proc FAR
  89.     ELSE
  90. clkrate    proc NEAR
  91.     ENDIF
  92. ; load counter 0 of 8253:
  93.     push    ax
  94.     mov    al, 00110110b    ; square wave mode
  95.     out    43h, al
  96.     pop    ax
  97.     out    40h, al
  98.     xchg    ah, al
  99.     out    40h, al
  100.     xchg    ah, al
  101.     ret
  102. clkrate endp
  103.  
  104.  
  105. ;   _SetInt( state)
  106. ;
  107. ;    enable/disable CPU interrupt.
  108. ;
  109. BEGIN  SetInt
  110.  
  111. Sintframe struc
  112.     dw    (?)
  113.     db    CPSIZE DUP (?)
  114. state    dw    (?)            ; interrupt state
  115. Sintframe ends
  116.     push    bp
  117.     mov    bp, sp
  118.  
  119.     cmp    [ bp].state, 0
  120.     jne    s_on
  121. ; off:
  122.     cli
  123.     jmp    s_end
  124. s_on:
  125.     sti
  126. s_end:
  127.     pop    bp
  128.     ret
  129.  
  130. P_END  SetInt
  131.  
  132.  
  133.  
  134.  
  135. ;   _SetClkRate( unsigned count)
  136. ;
  137. ;    Initialize interrupt rate to (1.119 MHz / count) cycles/sec.
  138. ;
  139. BEGIN SetClkRate
  140.  
  141. scrframe struc
  142.     dw    (?)
  143.     db    CPSIZE DUP (?)
  144. divid    dw    (?)            ; timer's divider
  145. scrframe ends
  146.     push    bp
  147.     mov    bp, sp
  148.  
  149.     mov    ax, [ bp].divid
  150.     pushf
  151.     cli    
  152.     mov    CS:clkdivl, ax
  153.     cmp    ax, 1
  154.     mov    CS:clkdivh, 0
  155.     adc    CS:clkdivh, 0
  156.     call    clkrate
  157.     popf
  158.     pop    bp
  159.     ret
  160. P_END  SetClkRate
  161.  
  162.  
  163.  
  164. ; Install clock-driver (soft int-08, timer-0).
  165. ; Save a copy of DS.
  166. ;
  167. BEGIN  clk_install
  168.  
  169. ; install clock interrupt handler
  170.     push    ax
  171.     push    dx
  172.  
  173. ; init. clk variables:
  174.     xor    ax, ax
  175.     call    clkrate
  176.     mov    CS:clkdivh, 1
  177.     mov    CS:clkdivl, ax
  178.     mov    CS:clkmod, ax
  179.  
  180. ; init flag:
  181.     mov    cs:user_routine_on, 0
  182.  
  183. ; save application DS:
  184.     mov    ax, ds
  185.     mov    cs:appl_ds, ax
  186.  
  187. ; save current int. vector
  188.     push    es
  189.     mov    ah, 35h
  190.     mov    al, clk_int
  191.     int    21h            ; get old vector
  192.     assume es:nothing
  193.     mov    CS:int08.regip, bx
  194.     mov    CS:int08.regcs, es
  195.     pop    es
  196. ; install interrupt intercept vector:
  197.     push    ds
  198.     mov    ah, 25h
  199.     mov    al, clk_int
  200.     mov    dx, offset clkint
  201.     mov    bx, CS
  202.     mov    ds, bx
  203.     int    21h            ; set int. vector
  204.     pop    ds
  205.     pop    dx
  206.     pop    ax
  207.  
  208.     ret
  209. P_END  clk_install
  210.  
  211.  
  212.  
  213. ;   _clk_uninstall()
  214. ;
  215. BEGIN  clk_uninstall
  216.  
  217.     xor    ax, ax
  218.     call    clkrate
  219. ; reset int. vector:
  220.     push    ds
  221.     mov    ah, 25h
  222.     mov    al, clk_int
  223.     lds    dx, CS:int08
  224.     int    21h            ; set vector ...
  225.     pop    ds
  226.     ret
  227. P_END  clk_uninstall
  228.  
  229.  
  230.  
  231.  
  232. ;   _StartTimeOut( delay)
  233. ;
  234. ;    Initialize count-down delay to 'delay'.
  235. ;
  236.  
  237. BEGIN  StartTimeOut
  238.  
  239. istad    struc
  240.     dw    (?)
  241.     db    CPSIZE DUP (?)
  242. delay    dw    (?)            ; delay before doing the next call
  243. istad    ends
  244.  
  245.     push    bp
  246.     mov    bp, sp
  247.     pushf
  248.     cli
  249.     mov     ax, [ bp].delay
  250.     mov     cs:soundDelay, ax
  251.     popf
  252.     pop    bp
  253.     ret
  254.  
  255. P_END  StartTimeOut
  256.  
  257.  
  258.  
  259. ;     clkint
  260. ;
  261. ; int-08 Interrupt Driver routine.
  262. ;
  263. ; Check for roll-over of 65536 cycles ( 18.2 hz ) and call
  264. ; old driver if so.
  265. ; Count-down delay variable, and if zero, call routine 'TimeOut()'
  266. ; & set the new delay.
  267. ;
  268. clkint    proc FAR
  269.  
  270.     push    ax
  271.  
  272. ; check for roll-over of 65536 cycles ( 18.2 hz )
  273.     mov    ax, CS:clkdivl
  274.     add    CS:clkmod, ax
  275.     mov    ax, CS:clkdivh
  276.     adc    ax, 0
  277.     jnz    clkint8
  278. ; not yet time, skip original interrupt
  279.     mov    al, 00100000b
  280.     out    20h, al            ; 8259 ...
  281.     jmp    clkint7
  282. ; do the original interrupt:
  283. clkint8    label    near
  284.     pushf
  285.     call    CS:int08
  286.  
  287. clkint7    label    near
  288.  
  289.     dec    CS:soundDelay        ; 16 bits unsigned counter
  290.     jnz    clkint_end
  291.  
  292. ; to avoid a reentrant call
  293.     cmp    CS:user_routine_on, 0
  294.     jnz    clkint_end        ; already active ...
  295.  
  296. ; end of delay. Prepare environment before calling TimeOut()
  297. ; (allocate temporary stack, set segment registers).
  298. ;
  299.  
  300. ; save all registers...    
  301.     push    bx
  302.     push    cx
  303.     push    dx
  304.     push    ds
  305.     push    es
  306.     push    si
  307.     push    di
  308.     push    bp
  309.  
  310. ; save active stack pointers
  311.     mov    cs:old_ss, ss
  312.     mov    cs:old_sp, sp
  313.  
  314. ; get application's DS
  315.     mov    ax, cs:appl_ds
  316.     mov    es, ax
  317.     mov    ds, ax
  318.  
  319. ; set new stack:
  320.     mov    ss, ax
  321.     mov    sp, offset DGROUP:interrupt_stack_top
  322.  
  323.  
  324. go_user    label near
  325. public go_user
  326.  
  327. ; protect call with flag
  328.     inc    CS:user_routine_on
  329.  
  330. ; call the C routine
  331.     sti
  332.     IF MICROSOFT
  333.     call    _TimeOut         ; time-out driver ... ==> AX: new delay
  334.     ELSE
  335.     call    TimeOut         ; time-out driver ... ==> AX: new delay
  336.     ENDIF
  337.  
  338.     cli
  339.     dec    CS:user_routine_on
  340.  
  341. ; compute new delay
  342.     mov    bx, CS:soundDelay
  343.     neg    bx                ; # of interrupt since call to TimeOut()
  344.     cmp    bx, ax                ; time-out ?
  345.     jb    clk_delay_ok            ; no ...
  346.  
  347. ; we must recall TimeOut immediately
  348.     mov    CS:soundDelay, 0
  349.     jmp    go_user
  350.  
  351. clk_delay_ok    label near
  352.     add    CS:soundDelay, ax        ; leftover delay count
  353.  
  354. ; restore stack
  355.     mov    bx, CS:old_ss
  356.     mov    ss, bx
  357.     mov    sp, CS:old_sp
  358.  
  359.     sti
  360.  
  361.     pop    bp
  362.     pop    di
  363.     pop    si
  364.     pop    es
  365.     pop    ds
  366.     pop    dx
  367.     pop    cx
  368.     pop    bx
  369.  
  370. clkint_end    label near
  371.     pop    ax
  372.     iret
  373. clkint    endp
  374.  
  375.  
  376.   IF MICROSOFT
  377.     ENDPS  <TIMER>
  378.   ELSE
  379.     ENDPS
  380.   ENDIF
  381.  
  382.     end
  383.  
  384.